package com.usian.service.impl;


import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.usian.mapper.SearchItemMapper;
import com.usian.pojo.SearchItem;
import com.usian.service.SearchItemService;
import com.usian.utils.JsonUtils;
import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.IndicesClient;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
@Transactional
public class SearchItemServiceImpl implements SearchItemService {

    @Autowired
    SearchItemMapper searchItemMapper;


    @Autowired
    RestHighLevelClient restHighLevelClient;

    //索引名称
    @Value("${ES_INDEX_NAME}")
    private String ES_INDEX_NAME;
    //类型名称
    @Value("${ES_TYPE_NAME}")
    private String ES_TYPE_NAME;

    //private int i = 0;


    /**
     * 商品搜索
     *
     * @param q
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Override
    public List<SearchItem> searchItemList(String q, Integer pageNum, Integer pageSize) {
        try {
            SearchRequest searchRequest = new SearchRequest(ES_INDEX_NAME).types(ES_TYPE_NAME);
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            //查询名字，买点，描述，类别包括"q"的商品   multiMatchQuery:匹配多个字段
            searchSourceBuilder.query(QueryBuilders.multiMatchQuery(q, "item_title",
                    "item_desc", "item_sell_point", "item_category_name"));
            pageNum = (pageNum - 1) * pageSize;
            searchSourceBuilder.from(pageNum);
            searchSourceBuilder.size(pageSize);
            //高亮
            HighlightBuilder highlightBuilder = new HighlightBuilder();
            highlightBuilder.postTags("<font color='red'>");
            highlightBuilder.postTags("</font>");
            highlightBuilder.field("item_title");
            searchSourceBuilder.highlighter(highlightBuilder);
            searchRequest.source(searchSourceBuilder);
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            SearchHit[] hits = searchResponse.getHits().getHits();
            //返回查询结果
            List<SearchItem> list = new ArrayList<>();
            for (SearchHit hit : hits) {
                SearchItem searchItem = JsonUtils.jsonToPojo(hit.getSourceAsString(), SearchItem.class);
                Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                if (highlightFields != null && highlightFields.size() > 0) {
                    searchItem.setItem_title(highlightFields.get("item_title").
                            getFragments()[0].toString());
                }
                list.add(searchItem);
            }
            return list;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public int updateIndex(String msg) throws IOException {
        //根据id查询商品信息
        SearchItem item = searchItemMapper.getItemById(Long.valueOf(msg));

        SearchRequest searchRequest = new SearchRequest();
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(QueryBuilders.matchQuery("id", msg).operator(Operator.AND));
        searchRequest.source(searchSourceBuilder);

        SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        SearchHit[] hits = search.getHits().getHits();
        String searchId = "";
        for (SearchHit hit : hits) {
            searchId = hit.getId();
        }

        //修改商品到索引库
        UpdateRequest updateRequest = new UpdateRequest(ES_INDEX_NAME,ES_TYPE_NAME,searchId);
        updateRequest.doc(JsonUtils.objectToJson(item), XContentType.JSON);
        UpdateResponse update = restHighLevelClient.update(updateRequest);
        return update.getShardInfo().getFailed();
    }

    @Override
    public int insertIndex(String itemId) throws IOException {
        // 1、根据商品id查询商品信息。
        SearchItem searchItem = searchItemMapper.getItemById(Long.valueOf(itemId));
        //2、添加商品到索引库
        IndexRequest indexRequest = new IndexRequest(ES_INDEX_NAME, ES_TYPE_NAME);
        indexRequest.source(JsonUtils.objectToJson(searchItem), XContentType.JSON);
        IndexResponse indexResponse =
                restHighLevelClient.index(indexRequest,RequestOptions.DEFAULT);
        return indexResponse.getShardInfo().getFailed();


    }

    @Override
    public int deleteIndex(String msg) throws IOException {

        SearchRequest searchRequest = new SearchRequest();
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(QueryBuilders.matchQuery("id", msg).operator(Operator.AND));
        searchRequest.source(searchSourceBuilder);

        SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        SearchHit[] hits = search.getHits().getHits();
        String searchId = "";
        for (SearchHit hit : hits) {
            //获取文档数据的id
            searchId = hit.getId();
        }
        //创建删除索引对象
        DeleteRequest deleteRequest = new DeleteRequest(ES_INDEX_NAME,ES_TYPE_NAME,searchId);

        //创建响应对象
        DeleteResponse deleteResponse = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
        //得到响应结果
        return deleteResponse.getShardInfo().getFailed();
    }

    /**
     * 商品库导入索引库  mysql导入ES
     *
     * @return
     */
    @Override
    public Boolean importAll() {

        try {
            //索引库如果不存在就创建，如果存在存储数据
            if (!isExistsIndex()) {
                 createIndex();
            }

            Integer page = 1;
            Integer i = 0;
            while (true) {
                //从mysql把商品信息数据查出来
                PageHelper.startPage(page, 1000);
                List<SearchItem> findAll = searchItemMapper.getFindAll();
                if (findAll.size() == 0) {
                    return false;
                }

                PageInfo<SearchItem> info = new PageInfo<>(findAll);

                //数据导入es BulkRequest：批量插入add
                BulkRequest bulkRequest = new BulkRequest();
                for (SearchItem searchItem : findAll) {
                    //商品信息添加到bulkRequest中
                    bulkRequest.add(new IndexRequest(ES_INDEX_NAME, ES_TYPE_NAME).
                            source(JsonUtils.objectToJson(searchItem), XContentType.JSON));
                    i++;
                }
                //放入es仓库
                restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
                if (i >= info.getTotal()) {
                    break;
                }
                page++;
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


    /**
     * 索引库是否存在
     *
     * @return
     * @throws Exception
     */
    private boolean isExistsIndex() throws Exception {
        //获取索引库请求对象
        GetIndexRequest getIndexRequest = new GetIndexRequest();
        getIndexRequest.indices(ES_INDEX_NAME);
        return restHighLevelClient.indices().exists(getIndexRequest, RequestOptions.DEFAULT);
    }

    /**
     * 创建索引库
     *
     * @return
     * @throws Exception
     */
    private boolean createIndex() throws Exception {
        //创建索引请求对象，并设置索引名称
        CreateIndexRequest createIndexRequest = new CreateIndexRequest(ES_INDEX_NAME);
        //设置索引参数 number_of_shards：主分片数量  number_of_replicas：副本数量
        createIndexRequest.settings(Settings.builder().put("number_of_shards", 2)
                .put("number_of_replicas", 1));
        createIndexRequest.mapping(ES_TYPE_NAME, "{\n" +
                "  \"_source\": {\n" +
                "    \"excludes\": [\n" +
                "      \"item_desc\"\n" +
                "    ]\n" +
                "  },\n" +
                "  \"properties\": {\n" +
                "    \"item_title\": {\n" +
                "      \"type\": \"text\",\n" +
                "      \"analyzer\": \"ik_max_word\",\n" +
                "      \"search_analyzer\": \"ik_smart\"\n" +
                "    },\n" +
                "    \"item_sell_point\": {\n" +
                "      \"type\": \"text\",\n" +
                "      \"analyzer\": \"ik_max_word\",\n" +
                "      \"search_analyzer\": \"ik_smart\"\n" +
                "    },\n" +
                "    \"item_price\": {\n" +
                "      \"type\": \"float\"\n" +
                "    },\n" +
                "    \"item_image\": {\n" +
                "      \"type\": \"text\",\n" +
                "      \"index\": false\n" +
                "    },\n" +
                "    \"item_category_name\": {\n" +
                "      \"type\": \"keyword\"\n" +
                "    },\n" +
                "    \"item_desc\": {\n" +
                "      \"type\": \"text\",\n" +
                "      \"analyzer\": \"ik_max_word\",\n" +
                "      \"search_analyzer\": \"ik_smart\"\n" +
                "    }\n" +
                "  }\n" +
                "}", XContentType.JSON);
        //创建操作客户端
        IndicesClient indices = restHighLevelClient.indices();
        //创建响应对象
        CreateIndexResponse createIndexResponse = indices.create(createIndexRequest, RequestOptions.DEFAULT);
        //创建成功返回true，否则返回false
        return createIndexResponse.isAcknowledged();
    }

}
